﻿
Imports System.Runtime.CompilerServices
Imports osi.root.connector
Imports osi.root.lock.slimlock
Imports osi.root.delegates

Public Module _locked
    <Extension()> Public Sub k_reader_locked(ByRef this As duallock, ByVal d As void)
        k_assert(Not d Is Nothing)
        this.reader_wait()
        Try
            d()
        Finally
            this.reader_release()
        End Try
    End Sub

    <Extension()> Public Function k_reader_locked(Of T)(ByRef this As duallock,
                                                        ByVal d As _do(Of T)) As T
        k_assert(Not d Is Nothing)
        Dim rtn As T = Nothing
        this.k_reader_locked(Sub() rtn = d())
        Return rtn
    End Function

    <Extension()> Public Sub k_writer_locked(ByRef this As duallock, ByVal d As void)
        k_assert(Not d Is Nothing)
        this.writer_wait()
        Try
            d()
        Finally
            this.writer_release()
        End Try
    End Sub

    <Extension()> Public Function k_writer_locked(Of T)(ByRef this As duallock,
                                                        ByVal d As _do(Of T)) As T
        Dim rtn As T = Nothing
        this.k_writer_locked(Sub() rtn = d())
        Return rtn
    End Function

    <Extension()> Public Sub k_locked(Of T As islimlock)(ByRef this As T, ByVal d As void)
        k_assert(Not this Is Nothing)
        k_assert(Not d Is Nothing)
        this.wait()
        Try
            d()
        Finally
            this.release()
        End Try
    End Sub

    <Extension()> Public Function k_locked(Of T As islimlock, OT) _
                                          (ByRef this As T,
                                           ByVal d As _do(Of OT)) As OT
        k_assert(Not this Is Nothing)
        k_assert(Not d Is Nothing)
        Dim rtn As OT = Nothing
        this.k_locked(Sub() rtn = d())
        Return rtn
    End Function

    <Extension()> Public Sub k_reenterable_locked(Of T As ilock) _
                                                 (ByRef this As T, ByVal d As void)
        k_assert(Not this Is Nothing)
        k_assert(Not d Is Nothing)
        If this.held_in_thread() Then
            d()
        Else
            this.k_locked(d)
        End If
    End Sub

    <Extension()> Public Function k_reenterable_locked(Of T As ilock, OT) _
                                                      (ByRef this As T,
                                                       ByVal d As _do(Of OT)) As OT
        k_assert(Not d Is Nothing)
        Dim rtn As OT = Nothing
        k_reenterable_locked(this, Sub() rtn = d())
        Return rtn
    End Function

    <Extension()> Public Sub k_reenterable_locked(ByRef this As slimlock.monitorlock, ByVal d As void)
        k_locked(this, d)
    End Sub

    <Extension()> Public Function k_reenterable_locked(Of T)(ByRef this As slimlock.monitorlock,
                                                             ByVal d As _do(Of T)) As T
        Return k_locked(this, d)
    End Function

    <Extension()> Public Sub k_reenterable_locked(ByRef this As lock.monitorlock, ByVal d As void)
        k_locked(this, d)
    End Sub

    <Extension()> Public Function k_reenterable_locked(Of T)(ByRef this As lock.monitorlock,
                                                             ByVal d As _do(Of T)) As T
        Return k_locked(this, d)
    End Function

    Public Sub k_assert_in_lock(Of T As ilock)(ByRef l As T)
        k_assert(l.held_in_thread())
    End Sub
End Module
